装饰者模式 Decorator Pattern

设计原则 五:

开放-关闭原则,类应该对拓展开放,对修改关闭。

定义装饰者模式

装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

Java 装饰者者模式的应用,Java I/O 流的

  1. 装饰者和被装饰对象有相同的超类型。

  2. 你可以用一个或多个装饰者包装一个对象。

  3. 既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合, 可以用装饰过的对象代替它。

  4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。(重要)

  5. 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰 对象。

类图

例图

装饰者类解析

1
2
3
4
5
6
7
8
9
10
11
package headfirst.decorator.starbuzz;

public abstract class Beverage {
String description = "Unknown Beverage";

public String getDescription() {
return description;
}

public abstract double cost();
}
1
2
3
4
5
package headfirst.decorator.starbuzz;

public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package headfirst.decorator.starbuzz;

public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}

public double cost() {
return .99;
}
}

package headfirst.decorator.starbuzz;

public class Decaf extends Beverage {
public Decaf() {
description = "Decaf Coffee";
}

public double cost() {
return 1.05;
}
}

package headfirst.decorator.starbuzz;

public class Espresso extends Beverage {

public Espresso() {
description = "Espresso";
}

public double cost() {
return 1.99;
}
}

package headfirst.decorator.starbuzz;

public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}

public double cost() {
return .89;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package headfirst.decorator.starbuzz;

public class Milk extends CondimentDecorator {
Beverage beverage;

public Milk(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Milk";
}

public double cost() {
return .10 + beverage.cost();
}
}

package headfirst.decorator.starbuzz;

public class Mocha extends CondimentDecorator {
Beverage beverage;

public Mocha(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Mocha";
}

public double cost() {
return .20 + beverage.cost();
}
}

package headfirst.decorator.starbuzz;

public class Soy extends CondimentDecorator {
Beverage beverage;

public Soy(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Soy";
}

public double cost() {
return .15 + beverage.cost();
}
}

package headfirst.decorator.starbuzz;

public class Whip extends CondimentDecorator {
Beverage beverage;

public Whip(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Whip";
}

public double cost() {
return .10 + beverage.cost();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package headfirst.decorator.starbuzz;

public class StarbuzzCoffee {

public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());

Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());

Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()
+ " $" + beverage3.cost());
}
}